/*
*	Author:		Brian Bousquet-Smith and Chaz Godwin
*	Project: 	OBDII Interpretter	
*	Description	Takes information from the OBDII Bus and outputs it
*			into a human readable format
*	Date:		Fall 2011
*/

#include <avr/io.h>
#include <avr/iom164.h> 
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/********************************************************************
				Defines
********************************************************************/

// LCD Initialization

#define LCD_HELLO	0xA3
#define LCD_INIT	0xA5
#define LCD_INIT_ACK	0xAA

// LCD Functions and Controls

#define CONTROL 	0x9F
#define CHARACTER	0xFE
#define BACKLIGHT_ON	0x81
#define LCD_ON		0x83
#define LCD_CLEAR	0x65
#define DISPLAY_ON	0x64
#define GO_HOME		0x61
#define CURSOR_ON	0x67
#define BLINK_ON	0x69
#define LEFT_TO_RIGHT	0x70
#define AUTO_SCROLL	0x6D

/*******************************************************************
		Function Prototypes and Global Variables
*******************************************************************/

// Main Program Functions

void power_on ();
void get_data();

// Initialization

void serial_init();
void lcd_init();
void obd_init();

// LCD Functions

void backlight_on();
void lcd_on();
void lcd_clear();
void display_on();
void return_home();
void cursor_on();
void blink_on();
void left_to_right();
void auto_scroll();
void print_lcd(char data[]);

// Serial Functions

void lcd_transmit(unsigned char data);
char lcd_receive();
void lcd_flush();
void obd_transmit(unsigned char data);
char obd_receive();

// Global Varaibles

char check[] = {'C', '&', 'B', ' ', '2', '0', '1', '1'};

int main(void){
	serial_init(); // Initialize Serial
	power_on(); // Turn Power Light On
	while(lcd_init() != 0);	// Waits for LCD to be initialized correctly
	while(elm_init() != 0); // Waits for ELM to be initialized correctly
	while(1){
		get_data();
	}		
} 

void power_on (){
/*
*	Purpose: Turn on power LCD
*	Input: Nothing
*	Output: Nothing
*/

	DDRA=0xff;
	DDRD=0xff;
	PORTA = 0x01;

}

int lcd_init(){
/*
*	Purpose: To initialize the LCD
*	Input: Nothing
*	Output: Error codes:
*		0 - Working Correctly
*		-1 - Didn't return acknowledge byte when asked
*/

	while( lcd_receive() != LCD_HELLO);	// Wait until LCD sends "Hello"
	
	lcd_on();
	lcd_transmit(LCD_INIT);
	if( lcd_receive == LCD_INIT_ACK){		
		backlight_on();
		lcd_clear();
		return_home();
		cursor_on();
		left_to_right();
		lcd_print(check);
		_delay_ms(4000);
		lcd_clear();
		return_home();
		return 0;
	}
	else{
		return -1;
	}
}

int obd_init(){
/*
*	Purpose: To initialize the ELM chip
*	Input: Nothing
*	Output: Error codes:
*		0 - Successful
*		-1 - Echo error
*		
*/
	
	char receive_byte;
	char count = 0;
	char receive_bytes[];

	obd_transmit('A');
	if (obd_receive() != 'A') return -1;	// Grabs echo
	obd_transmit('T');
	if (obd_receive() != 'T') return -1;	// Grabs echo
	obd_transmit('Z'); 
	if (obd_receive() != 'Z') return -1;	// Grabs echo
	while( (receive_byte = obd_receive()) != 'E');
	while ( receive_byte != 0x3E){
		receive_bytes[count] = receive_byte;
		count++;
	}
	print_lcd(receive_bytes);
	_delay_ms(2000);
	lcd_clear();
	return_home();
}


void get_data (){
	int flag = 0;
	unsigned char data, data1;
	PORTA = 0x01;
	data = lcd_receive();	


			// Autoscroll
			
	//		lcd_transmit(CONTROL);
	//		lcd_transmit(0x6D);

			//while(1){}
		//	lcd_transmit(CONTROL);
		//	lcd_transmit(0x6C);
			// Set cursor

		/*	lcd_transmit(CONTROL);
			lcd_transmit(0xFF);
			PORTA = 0x06;
			while( (data = lcd_receive()) != 0x5A);
			lcd_transmit(0x80);
			lcd_transmit(0x00);
						
			// Set cursor again

			lcd_transmit(CONTROL);
			lcd_transmit(0xFF);
			while( (data = lcd_receive()) != 0x5B);
			lcd_transmit(0x80);
			lcd_transmit(0x00);*/
			
			int j = 0;
			long i = 0;
			PORTA = 0x03;
			
			lcd_flush();
			lcd_transmit(CHARACTER);
			_delay_ms(20);
			lcd_flush();
			lcd_transmit('s');
			lcd_transmit('u');
			lcd_transmit('c');
			lcd_transmit('k');
			lcd_transmit(' ');
			lcd_transmit('i');
			lcd_transmit('t');
			lcd_transmit(' ');
			lcd_transmit('b');
			lcd_transmit('r');
			lcd_transmit('i');
			lcd_transmit('a');
			lcd_transmit('n');
			lcd_transmit(' ');
			_delay_ms(4000);
			lcd_transmit(CONTROL);
			lcd_transmit(0x65);
			lcd_transmit(CHARACTER);
			unsigned char x;
			//do{
			//	x = obd_receive();
			//	lcd_transmit(x);
			//}while(x!=0x3E);
			lcd_transmit(CONTROL);
			lcd_transmit(0x65);
			lcd_transmit(CONTROL);
			lcd_transmit(0x61);
			_delay_ms(2000);
			PORTA = 0x01;
			obd_transmit('A');
			_delay_ms(20);
			obd_receive();
			obd_transmit('T');
			_delay_ms(20);
			lcd_transmit(obd_receive());
			obd_transmit('Z');
			_delay_ms(20);
			lcd_transmit(obd_receive());
			obd_transmit(0x0D);
			_delay_ms(20);
			lcd_transmit(obd_receive());
			lcd_transmit(CHARACTER);
			/*int m;
			int b;
			int tmp;
			int count = 0;
			char data2[30];
			do{
				data2[count] = obd_receive();
				if(data2[count] == 0x3E) flag = 1;
				count++;
			}while(flag != 1);
			lcd_transmit(CHARACTER);
			lcd_transmit(count+48);
			PORTA = 0x01;
			_delay_ms(4000);
			PORTA = 0x04;*/
			/*for(b=0;b<count;b++){
				lcd_transmit(CHARACTER);
				for(m=0;m<8;m++){
					tmp =( ((data2[b]&mask[m])>>m)+48);
					lcd_transmit(tmp);
				}
				_delay_ms(3000);
				lcd_transmit(CONTROL);
				lcd_transmit(0x65);
				lcd_transmit(CONTROL);
				lcd_transmit(0x61);
			}
			while(1) PORTA = 0x07;*/
			int y;
			while((y = obd_receive()) != 'E');
			lcd_transmit(y);
			do{
				int n;
				x = obd_receive();
				
				lcd_transmit(x);
			}while(x!=0x3E);
			//x = obd_receive();
			//PORTA = 0x02;
			//lcd_transmit(CHARACTER);
			//lcd_transmit(x);
			//x = obd_receive();
			//lcd_transmit(CHARACTER);
			//lcd_transmit(x);
			//PORTA = 0x03;
			//PORTA = 0x07;
			//_delay_ms(20);
			PORTA = 0x07;
		
			_delay_ms(4000);				
			//while(1){}
			 
			
			PORTA = 0x07;
		}
	}	 
}

void serial_init(){

//	PRR0 |= (0<<PRUSART1)|(0<<PRUSART0); // Power Reduction Off

	UCSR0A |= (1<<U2X0);
	UCSR0B |= (1<<RXEN0)|(1<<TXEN0);
	UCSR0C |= (0<<USBS0)|(3<<UCSZ00);
	UBRR0H = 0;
	UBRR0L = 12;


	UCSR1A |= (1<<U2X1);
	UCSR1B |= (1<<RXEN1)|(1<<TXEN1); // Allow transmit and receive
	UCSR1C |= (1<<USBS1)|(3<<UCSZ10); // 8 Bit 2 Stop Bits
	UBRR1H = 0;
	UBRR1L = 12; // 9600 Baud
}
void print_lcd (char buffer[]){

/*
 * *       Purpose: Prints string of characters to the LCD
 * *       Input: String of characters desired
 * *       Output: Nothing
 * */

        int i;
        for(i=0;i<sizeof(buffer);i++){
		lcd_transmit(CHARACTER);
                lcd_transmit(buffer[i]);
        }
        return;
}


void lcd_transmit (unsigned char data){
	while( !(UCSR1A & (1<<UDRE1)));
	UDR1 = data;
}

char lcd_receive (void){
	while (!(UCSR1A & (1<<RXC1)));
	return UDR1;
}	

void obd_transmit (unsigned char data){
	while( !(UCSR0A & (1<<UDRE0)));
	UDR0 = data;
}

char obd_receive (void){
	while (!(UCSR0A & (1<<RXC0)));
	return UDR0;
}

void lcd_flush (void){
	char tmp;
	while (UCSR1A & (1<<RXC1) ) tmp = UDR1;
}

void backlight_on (void){

/*
*	Purpose: Turn the backlight on the LCD
*	Input: None
*   Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x81);
}	

void lcd_on (void){

/*
*	Purpose: Turn the LCD on
*   Input: None
*   Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x83);
}	

void lcd_clear (void){

/*
*	Purpose: Clears the LCD
*   Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x65);
}	

void display_on (void){

/*
*	Purpose: Turns the LCD display on
*	Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x64);
}	
	
void return_home (void){

/*
*	Purpose: Returns the LCD cursor to the beginning of the LCD
*	Input: None
*	Output: None
*/	
	lcd_transmit(CONTROL);
	lcd_transmit(0x61);
}	

void cursor_on (void){

/*
*	Purpose: Turns the LCD cursor on
*	Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x67);
}	

void blink_on (void){

/*
*	Purpose: Turns a LCD blinking cursor on
*	Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x69);
}

void left_to_right (void){
	
/*
*	Purpose: Causes the LCD writing to go from left to right
*	Input: None
*	Output: None
*/				

	lcd_transmit(CONTROL);
	lcd_transmit(0x70);
}	

void auto_scroll (void){

/*
*	Purpose: Causes the cursor to write next to the previous character on the LCD
*	Input: None
*   Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x6D);
}	
	
void print_lcd (char buffer[]){

/*
*	Purpose: Prints string of characters to the LCD
*	Input: String of characters desired
*	Output: Nothing
*/

	int i;
	for(i=0;i<sizeof(buffer);i++){
		lcd_transmit(buffer[i]);
	}
	return;
}

